Documentation and a couple of tidies.
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+import traceback
from StringIO import StringIO
from twisted.protocols import http
val = None
try:
dom = self.xd.domain_get(x)
+ if not dom: raise KeyError('No such domain')
val = SrvDomain(dom)
except KeyError, ex:
print 'SrvDomainDir>', ex
return v
def op_create(self, op, req):
+ """Create a domain.
+ Expects the domain config in request parameter 'config' in SXP format.
+ """
ok = 0
try:
configstring = req.args.get('config')[0]
config = pin.get_val()
ok = 1
except Exception, ex:
- print 'op_create>', ex
+ print 'op_create> Exception in config', ex
+ traceback.print_exc()
if not ok:
req.setResponseCode(http.BAD_REQUEST, "Invalid configuration")
return "Invalid configuration"
deferred.addCallback(self._cb_op_create, configstring, req)
return deferred
except Exception, ex:
- raise
- #return ['err', str(ex) ]
- #req.setResponseCode(http.BAD_REQUEST, "Error creating domain")
- #return str(ex)
+ print 'op_create> Exception creating domain:'
+ traceback.print_exc()
+ req.setResponseCode(http.BAD_REQUEST, "Error creating domain")
+ return str(ex)
#return error.ErrorPage(http.BAD_REQUEST,
# "Error creating domain",
# str(ex))
return val
def op_restore(self, op, req):
+ """Restore a domain from file.
+ """
fn = FormFn(self.xd.domain_restore,
[['file', 'str']])
val = fn(req.args)
req.write('</ul>')
def form(self, req):
+ """Generate the form(s) for domain dir operations.
+ """
req.write('<form method="post" action="%s" enctype="multipart/form-data">'
% req.prePathURL())
req.write('<button type="submit" name="op" value="create">Create Domain</button>')
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
from twisted.internet import defer
from xen.xend import sxp
self.registerChannel()
def createInstance(self, dom, recreate=0):
+ """Create a block device controller for a domain.
+
+ dom domain
+ recreate if true it's a recreate (after xend restart)
+ """
d = self.addDeferred()
blkif = self.getInstanceByDom(dom)
if blkif:
return d
def getDomainDevices(self, dom):
+ """Get the block devices for a domain.
+
+ dom domain
+
+ returns devices
+ """
blkif = self.getInstanceByDom(dom)
return (blkif and blkif.getDevices()) or []
def getDomainDevice(self, dom, vdev):
+ """Get a block device from a domain.
+
+ dom domain
+ vdev device index
+
+ returns device
+ """
blkif = self.getInstanceByDom(dom)
return (blkif and blkif.getDevice(vdev)) or None
def setControlDomain(self, dom, recreate=0):
+ """Set the back-end block device controller domain.
+
+ dom domain
+ recreate if true it's a recreate (after xend restart)
+ """
if self.dom == dom: return
self.deregisterChannel()
if not recreate:
self.attached = 0
self.dom = dom
self.registerChannel()
- #
- #if xend.blkif.be_port:
- # xend.blkif.recovery = True
- #xend.blkif.be_port = xend.main.port_from_dom(dom)
def getControlDomain(self):
+ """Get the back-end block device controller domain.
+ """
return self.dom
def reattachDevice(self, dom, vdev):
+ """Reattach a device (on changing control domain).
+
+ dom domain
+ vdev device index
+ """
blkif = self.getInstanceByDom(dom)
if blkif:
blkif.reattachDevice(vdev)
return attached
def reattached(self):
+ """Notify all block interface we have been reattached
+ (after changing control domain).
+ """
for blkif in self.getInstances():
blkif.reattached()
return val
def destroy(self):
- print 'BlkDev>destroy>', self.vdev
PrettyPrint.prettyprint(self.sxpr())
self.controller.send_be_vbd_destroy(self.vdev)
"""
def __init__(self, factory, dom):
- #print 'BlkifController> dom=', dom
controller.Controller.__init__(self, factory, dom)
self.devices = {}
self.attached = 1
self.evtchn = None
self.registerChannel()
- #print 'BlkifController<', 'dom=', self.dom, 'idx=', self.idx
def sxpr(self):
val = ['blkif', ['dom', self.dom]]
return val
def lostChannel(self):
- print 'BlkifController>lostChannel>', 'dom=', self.dom
- #self.destroyDevices()
controller.Controller.lostChannel(self)
def getDevices(self):
def attachDevice(self, vdev, mode, segment, recreate=0):
"""Attach a device to the specified interface.
+
+ vdev device index
+ mode read/write mode
+ segment segment
+ recreate if true it's being recreated (after xend restart)
+
+ returns deferred
"""
- #print 'BlkifController>attach_device>', self.dom, vdev, mode, segment
dev = self.addDevice(vdev, mode, segment)
if not dev: return -1
if recreate:
return d
def destroy(self):
- print 'BlkifController>destroy> dom=', self.dom
def cb_destroy(val):
self.send_be_destroy()
d = self.factory.addDeferred()
d.addCallback(cb_destroy)
self.send_be_disconnect()
- #self.destroyDevices()
def destroyDevices(self):
for dev in self.getDevices():
self.factory.writeRequest(msg)
pass
- #def recv_fe_interface_status_changed(self, msg, req):
- # (hnd, status, chan) = unpackMsg('blkif_fe_interface_status_changed_t', msg)
- # print 'recv_fe_interface_status_changed>', hnd, status, chan
- # pass
-
def send_fe_interface_status_changed(self):
msg = packMsg('blkif_fe_interface_status_changed_t',
{ 'handle' : 0,
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
from xen.lowlevel import xu
from messages import msgTypeName
self.notifier = xu.notifier()
def addChannel(self, channel):
- """Add a channel.
+ """Add a channel. Registers with the notifier.
"""
idx = channel.idx
self.channels[idx] = channel
self.notifier.bind(idx)
- # Try to wake it up
- #self.notifier.unmask(idx)
- #channel.notify()
def getChannel(self, idx):
"""Get the channel with the given index (if any).
def delChannel(self, idx):
"""Remove the channel with the given index (if any).
+ Deregisters with the notifier.
"""
if idx in self.channels:
del self.channels[idx]
self.getRemotePort()))
def handleNotification(self):
+ """Process outstanding messages in repsonse to notification on the port.
+ """
if self.closed:
print 'handleNotification> Notification on closed channel', self
return
self.notify()
def notify(self):
+ """Notify the other end of the port that messages have been processed.
+ """
if self.closed: return
self.port.notify()
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from twisted.internet import reactor
from twisted.internet import protocol
from messages import *
from params import *
-"""Telnet binary option."""
-TRANSMIT_BINARY = '0'
-WILL = chr(251)
-IAC = chr(255)
-
class ConsoleProtocol(protocol.Protocol):
"""Asynchronous handler for a console TCP socket.
"""
self.loseConnection()
return
else:
- # KAF: A nice quiet successful connect. Don't bother with telnet
- # control sequence -- telnet is not the appropriate protocol here.
+ # KAF: A nice quiet successful connect.
#self.transport.write("Connected to console %d on domain %d\n"
# % (self.idx, self.controller.dom))
- #self.setTelnetTransmitBinary()
eserver.inject('xend.console.connect',
[self.idx, self.addr[0], self.addr[1]])
- def setTelnetTransmitBinary(self):
- """Send the sequence to set the telnet TRANSMIT-BINARY option.
- """
- self.write(IAC + WILL + TRANSMIT_BINARY)
-
def dataReceived(self, data):
if self.controller.handleInput(self, data):
self.loseConnection()
"""
def __init__(self, factory, dom, console_port):
- #print 'ConsoleController> dom=', dom, type(dom)
controller.Controller.__init__(self, factory, dom)
self.majorTypes = [ CMSG_CONSOLE ]
self.status = "new"
self.registerChannel()
self.listener = None
self.listen()
- #print 'ConsoleController<', 'dom=', self.dom, 'idx=', self.idx
def sxpr(self):
val =['console',
def close(self):
try:
- #print 'ConsoleController> close dom=', self.dom
self.status = "closed"
if self.conn:
self.conn.loseConnection()
self.listen()
def requestReceived(self, msg, type, subtype):
- #print '***Console', self.dom, msg.get_payload()
self.rbuf.write(msg.get_payload())
self.handleOutput()
def responseReceived(self, msg, type, subtype):
+ # Just ignore responses.
pass
def produceRequests(self):
Sends it to the connected console (if any).
"""
if self.closed():
- #print 'Console>handleOutput> closed'
return -1
if not self.conn:
- #print 'Console>handleOutput> not connected'
return 0
while not self.rbuf.empty():
try:
- #print 'Console>handleOutput> writing...'
bytes = self.conn.write(self.rbuf.peek())
if bytes > 0:
self.rbuf.discard(bytes)
except socket.error, error:
pass
- #print 'Console>handleOutput<'
return 0
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
from twisted.internet import defer
import channel
class CtrlMsgRcvr:
"""Abstract class for things that deal with a control interface to a domain.
+
+ Instance variables:
+
+ dom : the domain we are a control interface for
+ majorTypes: list of major message types we are interested in
+ subTypes : mapping of message subtypes to methods
+
+ channel : channel to the domain
+ idx : channel index
"""
self.idx = None
def requestReceived(self, msg, type, subtype):
+ """Dispatch a request to handlers.
+
+ msg message
+ type major message type
+ subtype minor message type
+ """
method = self.subTypes.get(subtype)
if method:
method(msg, 1)
% (msgTypeName(type, subtype), type, subtype)), self
def responseReceived(self, msg, type, subtype):
+ """Dispatch a response to handlers.
+
+ msg message
+ type major message type
+ subtype minor message type
+ """
method = self.subTypes.get(subtype)
if method:
method(msg, 0)
% (msgTypeName(type, subtype), type, subtype)), self
def lostChannel(self):
+ """Called when the channel to the domain is lost.
+ """
pass
def registerChannel(self):
+ """Register interest in our major message types with the
+ channel to our domain.
+ """
#print 'CtrlMsgRcvr>registerChannel>', self
self.channel = self.channelFactory.domChannel(self.dom)
self.idx = self.channel.getIndex()
self.channel.registerDevice(self.majorTypes, self)
def deregisterChannel(self):
+ """Deregister interest in our major message types with the
+ channel to our domain.
+ """
#print 'CtrlMsgRcvr>deregisterChannel>', self
if self.channel:
self.channel.deregisterDevice(self)
del self.channel
def produceRequests(self):
+ """Produce any queued requests.
+
+ return number produced
+ """
return 0
def writeRequest(self, msg):
+ """Write a request to the channel.
+ """
if self.channel:
self.channel.writeRequest(msg)
else:
print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self
def writeResponse(self, msg):
+ """Write a response to the channel.
+ """
if self.channel:
self.channel.writeResponse(msg)
else:
class ControllerFactory(CtrlMsgRcvr):
"""Abstract class for factories creating controllers.
Maintains a table of instances.
+
+ Instance variables:
+
+ instances : mapping of index to controller instance
+ dlist : list of deferreds
+ dom : domain
+ timeout : deferred timeout
"""
def __init__(self):
self.timeout = 10
def addInstance(self, instance):
+ """Add a controller instance (under its index).
+ """
self.instances[instance.idx] = instance
def getInstance(self, idx):
+ """Get a controller instance from its index.
+ """
return self.instances.get(idx)
def getInstances(self):
+ """Get a list of all controller instances.
+ """
return self.instances.values()
def getInstanceByDom(self, dom):
+ """Get the controller instance for the given domain.
+ """
for inst in self.instances.values():
if inst.dom == dom:
return inst
return None
def delInstance(self, instance):
- #print 'ControllerFactory>delInstance>', instance.idx
+ """Delete an instance from the table.
+ """
if instance.idx in self.instances:
- #print 'ControllerFactory>delInstance> remove', instance.idx
del self.instances[instance.idx]
def createInstance(self, dom, recreate=0):
+ """Create an instance. Define in a subclass.
+ """
raise NotImplementedError()
def instanceClosed(self, instance):
- #print 'ControllerFactory>instanceClosed>', instance.idx, instance
+ """Callback called when an instance is closed (usually by the instance).
+ """
self.delInstance(instance)
def addDeferred(self):
+ """Add a deferred object.
+
+ returns deferred
+ """
d = defer.Deferred()
if self.timeout > 0:
# The deferred will error if not called before timeout.
return d
def callDeferred(self, *args):
+ """Call the top deferred object
+
+ args arguments
+ """
if self.dlist:
d = self.dlist.pop(0)
d.callback(*args)
def errDeferred(self, *args):
+ """Signal an error to the top deferred object.
+
+ args arguments
+ """
if self.dlist:
d = self.dlist.pop(0)
d.errback(*args)
self.idx = None
def close(self):
+ """Close the controller.
+ """
self.deregisterChannel()
self.lostChannel()
def lostChannel(self):
- #print 'Controller>lostChannel>', self, self.factory
+ """The controller channel has been lost.
+ """
self.factory.instanceClosed(self)
class Dev:
-
+ """Abstract class for a device attached to a device controller.
+ """
+
def __init__(self, controller):
self.controller = controller
self.props = {}
if k in self.props:
del self.props[k]
- #def __repr__(self):
- # return str(self.sxpr())
-
def sxpr(self):
raise NotImplementedError()
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
import channel
import controller
from messages import *
"""
def createInstance(self, dom):
+ """Create a domain controller.
+
+ dom domain
+
+ returns domain controller
+ """
d = DomainController(self, dom)
self.addInstance(d)
return d
def getInstanceByDom(self, dom):
+ """Get a domain controller for a domain, creating if necessary.
+
+ dom domain
+
+ returns domain controller
+ """
for inst in self.instances.values():
if inst.dom == dom:
return inst
class DomainController(controller.Controller):
"""Generic controller for a domain.
+ Used for domain shutdown.
"""
+ """Map shutdown reasons to the message type to use.
+ """
reasons = {'poweroff' : 'shutdown_poweroff_t',
'reboot' : 'shutdown_reboot_t',
'suspend' : 'shutdown_suspend_t' }
print 'DomainController>', self, self.channel, self.idx
def shutdown(self, reason):
+ """Shutdown a domain.
+
+ reason shutdown reason
+ """
msgtype = self.reasons.get(reason)
if not msgtype:
raise ValueError('invalid reason:' + reason)
msg_formats.update(netif_formats)
#============================================================================
+# Domain shutdown message types.
+#============================================================================
+
CMSG_SHUTDOWN = 6
CMSG_SHUTDOWN_POWEROFF = 0
pass
def packMsg(ty, params):
+ """Pack a message.
+ Any 'mac' parameter is passed in as an int[6] array and converted.
+
+ ty message type name
+ params message parameter dict
+
+ returns xu message
+ """
if DEBUG: print '>packMsg', ty, params
(major, minor) = msg_formats[ty]
args = {}
return msg
def unpackMsg(ty, msg):
+ """Unpack a message.
+ Any mac addresses in the message are converted to int[6] array
+ in the return dict.
+
+ ty message type
+ msg xu message
+
+ returns parameter dict
+ """
args = msg.get_payload()
mac = [0, 0, 0, 0, 0, 0]
macs = []
return args
def msgTypeName(ty, subty):
+ """Convert a message type, subtype pair (ints) to a message type name (string).
+
+ ty integer message type
+ subty integer message subtype
+
+ returns message type name (or None)
+ """
for (name, info) in msg_formats.items():
if info[0] == ty and info[1] == subty:
return name
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
import random
from twisted.internet import defer
def createInstance(self, dom, recreate=0):
"""Create or find the network interface controller for a domain.
+
+ dom domain
+ recreate if true this is a recreate (xend restarted)
+
+ returns netif controller
"""
- #print 'netif>createInstance> dom=', dom
netif = self.getInstanceByDom(dom)
if netif is None:
netif = NetifController(self, dom)
return netif
def getDomainDevices(self, dom):
+ """Get the network device controllers for a domain.
+
+ dom domain
+
+ returns netif controller
+ """
netif = self.getInstanceByDom(dom)
return (netif and netif.getDevices()) or []
def getDomainDevice(self, dom, vif):
+ """Get a virtual network interface device for a domain.
+
+ dom domain
+ vif virtual interface index
+
+ returns NetDev
+ """
netif = self.getInstanceByDom(dom)
return (netif and netif.getDevice(vif)) or None
def setControlDomain(self, dom, recreate=0):
"""Set the 'back-end' device driver domain.
+
+ dom domain
+ recreate if true this is a recreate (xend restarted)
"""
if self.dom == dom: return
self.deregisterChannel()
self.attached = 0
self.dom = dom
self.registerChannel()
- #
- #if xend.netif.be_port.remote_dom != 0:
- # xend.netif.recovery = True
- # xend.netif.be_port = xend.main.port_from_dom(dom)
- #
def getControlDomain(self):
+ """Get the domain id of the back-end control domain.
+ """
return self.dom
def recv_be_create(self, msg, req):
netif.reattach_devices()
self.attached = 1
-## pl = msg.get_payload()
-## status = pl['status']
-## if status == NETIF_DRIVER_STATUS_UP:
-## if xend.netif.recovery:
-## print "New netif backend now UP, notifying guests:"
-## for netif_key in interface.list.keys():
-## netif = interface.list[netif_key]
-## netif.create()
-## print " Notifying %d" % netif.dom
-## msg = xu.message(
-## CMSG_NETIF_FE,
-## CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED, 0,
-## { 'handle' : 0, 'status' : 1 })
-## netif.ctrlif_tx_req(xend.main.port_from_dom(netif.dom),msg)
-## print "Done notifying guests"
-## recovery = False
-
class NetDev(controller.Dev):
"""Info record for a network device.
"""
return val
def get_vifname(self):
+ """Get the virtual interface device name.
+ """
return "vif%d.%d" % (self.controller.dom, self.vif)
def get_mac(self):
+ """Get the MAC address as a string.
+ """
return ':'.join(map(lambda x: "%x" % x, self.mac))
def vifctl_params(self):
'ipaddr': self.ipaddr }
def up(self, bridge=None, ipaddr=[]):
+ """Bring the device up.
+
+ bridge ethernet bridge to connect to
+ ipaddr list of ipaddrs to filter using iptables
+ """
self.bridge = bridge
self.ipaddr = ipaddr
Vifctl.up(self.get_vifname(), **self.vifctl_params())
def down(self):
+ """Bring the device down.
+ """
Vifctl.down(self.get_vifname(), **self.vifctl_params())
def destroy(self):
+ """Destroy the device's resources and disconnect from the back-end
+ device controller.
+ """
def cb_destroy(val):
self.controller.send_be_destroy(self.vif)
- print 'NetDev>destroy>', 'vif=', self.vif
- PrettyPrint.prettyprint(self.sxpr())
self.down()
d = self.controller.factory.addDeferred()
d.addCallback(cb_destroy)
self.controller.send_be_disconnect(self.vif)
- #self.controller.send_be_destroy(self.vif)
class NetifController(controller.Controller):
"""
def __init__(self, factory, dom):
- #print 'NetifController> dom=', dom
controller.Controller.__init__(self, factory, dom)
self.devices = {}
self.recv_fe_interface_connect,
}
self.registerChannel()
- #print 'NetifController<', 'dom=', self.dom, 'idx=', self.idx
def sxpr(self):
val = ['netif', ['dom', self.dom]]
return val
def randomMAC(self):
- # VIFs get a random MAC address with a "special" vendor id.
- #
- # NB. The vendor is currently an "obsolete" one that used to belong
- # to DEC (AA-00-00). Using it is probably a bit rude :-)
- #
- # NB2. The first bit of the first random octet is set to zero for
- # all dynamic MAC addresses. This may allow us to manually specify
- # MAC addresses for some VIFs with no fear of clashes.
+ """Generate a random MAC address.
+
+ The OUI (Organisation Unique Identifier) used is AA:00:00, which
+ is a currently unassigned one that used to belong to DEC.
+
+ The remaining 3 fields are random, with the first bit of the first
+ random field set 0.
+
+ returns array of 6 ints
+ """
mac = [ 0xaa, 0x00, 0x00,
random.randint(0x00, 0x7f),
random.randint(0x00, 0xff),
return mac
def lostChannel(self):
- print 'NetifController>lostChannel>', 'dom=', self.dom
- #self.destroyDevices()
+ """Method called when the channel has been lost.
+ """
controller.Controller.lostChannel(self)
def getDevices(self):
+ """Get a list of the devices.
+ """
return self.devices.values()
def getDevice(self, vif):
+ """Get a device.
+
+ vif device index
+
+ returns device (or None)
+ """
return self.devices.get(vif)
def addDevice(self, vif, vmac):
+ """Add a network interface. If vmac is None a random MAC is
+ assigned. If specified, vmac must be a string of the form
+ XX:XX:XX:XX:XX where X is hex digit.
+
+ vif device index
+ vmac device MAC
+
+ returns device
+ """
if vmac is None:
mac = self.randomMAC()
else:
mac = [ int(x, 16) for x in vmac.split(':') ]
if len(mac) != 6: raise ValueError("invalid mac")
- #print "attach_device>", "vif=", vif, "mac=", mac
dev = NetDev(self, vif, mac)
self.devices[vif] = dev
return dev
def destroy(self):
- print 'NetifController>destroy>', 'dom=', self.dom
+ """Destroy the controller and all devices.
+ """
self.destroyDevices()
def destroyDevices(self):
self.factory.writeRequest(msg)
def send_be_destroy(self, vif):
- print 'NetifController>send_be_destroy>', 'dom=', self.dom, 'vif=', vif
PrettyPrint.prettyprint(self.sxpr())
dev = self.devices[vif]
del self.devices[vif]